package com.cbs.utils;

import android.annotation.TargetApi;
import android.os.Build;
import com.cbs.log.L;
import com.google.gson.*;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.Type;
import java.security.InvalidKeyException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.zip.GZIPInputStream;
import java.util.zip.GZIPOutputStream;

/**
 * Created by broche on 4/22/14.
 */
public final class F {
    public static final class GZip {
        public static byte[] zip(byte[] data) {
            byte[] result = null;
            try {
                ByteArrayInputStream bais = new ByteArrayInputStream(data);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                GZIPOutputStream gos = new GZIPOutputStream(baos);
                byte[] buffer = new byte[2048];
                int readSize;
                while (-1 != (readSize = bais.read(buffer, 0, buffer.length))) {
                    gos.write(buffer, 0, readSize);
                }
                gos.finish();
                gos.flush();
                baos.flush();
                result = baos.toByteArray();
                bais.close();
                baos.close();
                gos.close();
            } catch (IOException e) {
                L.e(F.class.getName(), e.getMessage());
            }
            return result;
        }

        public static byte[] unZip(byte[] data) {
            byte[] result = null;
            try {
                ByteArrayInputStream bais = new ByteArrayInputStream(data);
                GZIPInputStream gis = new GZIPInputStream(bais);
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                byte[] buffer = new byte[2048];
                int readSize;
                while (-1 != (readSize = gis.read(buffer, 0, buffer.length))) {
                    baos.write(buffer, 0, readSize);
                }
                baos.flush();
                result = baos.toByteArray();
                gis.close();
                bais.close();
                baos.close();
            } catch (IOException e) {
                L.e(F.class.getName(), e.getMessage());
            }
            return result;
        }
    }

    public static final class Base64 {
        @TargetApi(Build.VERSION_CODES.FROYO)
        public static byte[] base64Encode(byte[] data) {
            return android.util.Base64.encode(data, android.util.Base64.DEFAULT);
        }

        @TargetApi(Build.VERSION_CODES.FROYO)
        public static byte[] base64Encode(byte[] data, int flags) {
            return android.util.Base64.encode(data, flags);
        }

        @TargetApi(Build.VERSION_CODES.FROYO)
        public static byte[] base64Decode(byte[] data) {
            return android.util.Base64.decode(data, android.util.Base64.DEFAULT);
        }

        @TargetApi(Build.VERSION_CODES.FROYO)
        public static byte[] base64Decode(byte[] data, int flags) {
            return android.util.Base64.decode(data, flags);
        }

        @TargetApi(Build.VERSION_CODES.FROYO)
        public static byte[] base64Decode(String data, int flags) {
            return android.util.Base64.decode(data, flags);
        }
    }

    public static final class Security {
        private final static String HMAC_SHA1 = "HmacSHA1";

        public static byte[] hmacSHA1(byte[] data, byte[] key) {
            byte[] result = null;
            SecretKeySpec signingKey = new SecretKeySpec(key, HMAC_SHA1);
            try {
                Mac mac = Mac.getInstance(HMAC_SHA1);
                mac.init(signingKey);
                result = mac.doFinal(data);
            } catch (NoSuchAlgorithmException | InvalidKeyException e) {
                L.e(F.class.getName(), e.getMessage());
            }
            return result;
        }

        private final static char hexDigits[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'};

        public static String md5(byte[] data) {
            String result = "";
            try {
                MessageDigest md = MessageDigest.getInstance("MD5");
                md.update(data);
                byte[] bresult = md.digest();
                result = bytes2String(bresult);
            } catch (NoSuchAlgorithmException e) {
                L.e(F.class.getName(), e.getMessage());
            }
            return result;
        }

        private static String bytes2String(byte[] data) {
            char[] c = new char[data.length * 2];
            for (int i = 0; i <= data.length - 1; i++) {
                byte b = data[i];
                c[i * 2] = hexDigits[b >> 4 & 0xF];
                c[i * 2 + 1] = hexDigits[b & 0xF];
            }
            return new String(c);
        }
    }

    public static final class Date {
        public static String format(double timestamp, String format) {
            SimpleDateFormat sdf = new SimpleDateFormat(format);
            sdf.setCalendar(Calendar.getInstance(TimeZone.getTimeZone("Asia/Shanghai")));
            return sdf.format(new java.util.Date((long) (timestamp * 1000)));
        }

        public static String description(double timestamp) {
            String result = "未知";
            double timeInterval = S.getTimeStamp() - timestamp;
            if (timeInterval < 60) {
                result = "1分钟内";
            } else if (timeInterval < 3600) {//1小时内
                result = (int) timeInterval / 60 + "分钟前";
            } else if (timeInterval < 3600 * 24) {//24小时内
                result = (int) timeInterval / 3600 + "小时前";
            } else if (timeInterval < 3600 * 24 * 2) {
                result = "昨天";
            } else if (timeInterval < 3600 * 24 * 3) {
                result = "2天前";
            } else if (timeInterval < 3600 * 24 * 4) {
                result = "3天前";
            } else if (timeInterval < 3600 * 24 * 5) {
                result = "4天前";
            } else if (timeInterval < 3600 * 24 * 6) {
                result = "5天前";
            } else if (timeInterval < 3600 * 24 * 7) {
                result = "6天前";
            } else if (timeInterval < 3600 * 24 * 15) {
                result = "1周前";
            } else if (timeInterval < 3600 * 24 * 16) {
                result = "2周前";
            } else if (timeInterval < 3600 * 24 * 31) {
                result = "半月前";
            } else {
                String date1 = format(S.getTimeStamp(), "yyyy-MM");
                String date2 = format(timestamp, "yyyy-MM");
                String[] tdate1 = date1.split("-");
                String[] tdate2 = date2.split("-");
                int year1 = Integer.parseInt(tdate1[0]);
                int year2 = Integer.parseInt(tdate2[0]);
                int month1 = Integer.parseInt(tdate1[1]);
                int month2 = Integer.parseInt(tdate2[1]);
                int monthCount = (year1 - year2 - 1) * 12 + (12 - month2) + month1;
                if (monthCount / 12 > 0) {
                    result = monthCount / 12 + "年前";
                } else {
                    result = monthCount + "月前";
                }
            }
            return result;
        }
    }

    public static String map2String(Map data, String itemSplitter, String sectionSplitter) {
        StringBuilder result = new StringBuilder();
        for (Object key : data.keySet()) {
            result.append(key);
            result.append(itemSplitter);
            result.append(data.get(key));
            result.append(sectionSplitter);
        }
        if (result.length() > 0) {
            result.delete(result.length() - sectionSplitter.length(), result.length());
        }
        return result.toString();
    }

    public static Map string2Map(String string, String itemSplitter, String sectionSplitter) {
        Hashtable<String, String> map = new Hashtable<>();
        String[] items = string.split(sectionSplitter);
        for (String item : items) {
            String[] ss = item.split(itemSplitter);
            map.put(ss[0], ss[1]);
        }
        return map;
    }

    public static Gson getGson() {
        return new GsonBuilder().registerTypeAdapter(Hashtable.class, new JsonDeserializer<Hashtable>() {
            public Hashtable deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context)
                    throws JsonParseException {
                Hashtable hashtable = new Hashtable();
                JsonObject jsonObject = json.getAsJsonObject();
                Set<Map.Entry<String, JsonElement>> entrySet = jsonObject.entrySet();
                for (Map.Entry<String, JsonElement> entry : entrySet) {
                    hashtable.put(entry.getKey(), entry.getValue());
                }
                return hashtable;
            }
        }).create();
    }
}